package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.SugarRecordType;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveLaboratory;
import org.dtrd.modules.archive.service.IDtrdEntRdLaboratoryService;
import org.dtrd.modules.control.entity.po.DtrdEntRdSigninTargetDetail;
import org.dtrd.modules.record.config.SugarConfig;
import org.dtrd.modules.record.config.SugarConfig.UplowType;
import org.dtrd.modules.record.entity.bean.ValueUplowBean;
import org.dtrd.modules.record.entity.po.*;
import org.dtrd.modules.record.mapper.DtrdEntRdUplowRecordMapper;
import org.dtrd.modules.record.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 血糖上下限 服务实现类
 * </p>
 *
 * @author QR
 * @since 2021-10-20
 */
@Service
@DS("multi-datasource1")
@Slf4j
public class DtrdEntRdUplowRecordServiceImpl extends ServiceImpl<DtrdEntRdUplowRecordMapper, DtrdEntRdUplowRecord> implements IDtrdEntRdUplowRecordService {

    @Autowired
    private ISugarRecordService sugarRecordService;
    @Autowired
    private IHeightWeightRecordService heightWeightRecordService;
    @Autowired
    private IWaistlineRecordService waistlineRecordService;
    @Autowired
    private IDtrdEntRdLaboratoryService laboratoryService;
    @Autowired
    private IBloodPressureRecordService bloodPressureRecordService;

    @Override
    public ValueUplowBean getSugarValueUpLowRecord(Integer doctorId, Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdUplowRecord> queryWrapper = getRecordQueryWrapper(doctorId, patientId);
        List<DtrdEntRdUplowRecord> records = this.list(queryWrapper);
        return wrapperUplowRecords(records);
    }

    @Override
    public Map<Date, Integer> getSugarReachStandard(Integer patientId, Date startDate, Date endDate) {
        // 查询血糖记录
        LambdaQueryWrapper<DtrdEntRdSigninSugarValue> wrapper1 = Wrappers.lambdaQuery(DtrdEntRdSigninSugarValue.class)
                .eq(DtrdEntRdSigninSugarValue::getPatientId, patientId)
                .ge(DtrdEntRdSigninSugarValue::getRecordDate, startDate)
                .le(DtrdEntRdSigninSugarValue::getRecordDate, endDate)
                .orderByAsc(DtrdEntRdSigninSugarValue::getSugarValueTimeTypeId);
        List<DtrdEntRdSigninSugarValue> sugarValues = sugarRecordService.list(wrapper1);
        // 没有血糖记录返回 0 %
        if (CollectionUtil.isEmpty(sugarValues)) {
            return null;
        }
//        LambdaQueryWrapper<DtrdEntRdUplowRecord> wrapper2 = Wrappers.lambdaQuery(DtrdEntRdUplowRecord.class)
//                .eq(DtrdEntRdUplowRecord::getPatientId, patientId)
//                .orderByAsc(DtrdEntRdUplowRecord::getUplowRecordLimitType);
//        List<DtrdEntRdUplowRecord> list = list(wrapper2)
        ValueUplowBean upLowRecord = getSugarValueUpLowRecord(patientId);

        HashMap<Date, Integer> map = new HashMap<>();
        Map<Date, List<DtrdEntRdSigninSugarValue>> dateToSugars = sugarValues.stream().collect(Collectors.groupingBy(DtrdEntRdSigninSugarValue::getRecordDate));
        for (Map.Entry<Date, List<DtrdEntRdSigninSugarValue>> entry : dateToSugars.entrySet()) {
            int reachStandardCount = 0;
            List<DtrdEntRdSigninSugarValue> sugarValueList = entry.getValue();

            // 空腹
            List<Float> values1 = getSugarValues(sugarValueList, Constant.SugarRecordType.BEFOREBREAKFAST);
            reachStandardCount += getReachStandardCount(values1, upLowRecord.getUpperValueLimosis(), upLowRecord.getLowerValueLimosis());

            // 睡前
            values1 =  getSugarValues(sugarValueList, Constant.SugarRecordType.BEFORESLEEP);
            reachStandardCount += getReachStandardCount(values1, upLowRecord.getUpperValueBeforeSleep(), upLowRecord.getLowerValueBeforeSleep());

            // 餐前
            values1 = getSugarValues(sugarValueList, Constant.SugarRecordType.BEFOREDINNER, Constant.SugarRecordType.BEFORELUNCH);
            reachStandardCount += getReachStandardCount(values1, upLowRecord.getUpperValueBeforeMeal(), upLowRecord.getLowerValueBeforeMeal());
            // 餐后
            values1 = getSugarValues(sugarValueList, Constant.SugarRecordType.AFTERBREAKFAST, Constant.SugarRecordType.AFTERLUNCH, Constant.SugarRecordType.AFTERDINNER);
            reachStandardCount += getReachStandardCount(values1, upLowRecord.getUpperValueAfterMeal(), upLowRecord.getLowerValueAfterMeal());

//            for (DtrdEntRdUplowRecord record : list) {
//                Float upper = record.getUplowRecordUpperValue();
//                Float lower = record.getUplowRecordLowerValue();
//                Integer limitType = record.getUplowRecordLimitType();
//                SugarConfig.UplowType type = UplowType.valueOf(limitType);
//                assert type != null;
//                switch (type) {
//                    case LIMOSIS:
//                        List<Float> values1 = getSugarValues(sugarValueList, Constant.SugarRecordType.BEFOREBREAKFAST);
//                        reachStandardCount += getReachStandardCount(values1, upper, lower);
//                        break;
//                    case BEFORE_MEAL:
//                        List<Float> values2 = getSugarValues(sugarValueList, Constant.SugarRecordType.BEFOREDINNER, Constant.SugarRecordType.BEFORELUNCH);
//                        reachStandardCount += getReachStandardCount(values2, upper, lower);
//                        break;
//                    case AFTER_MEAL:
//                        List<Float> values3 = getSugarValues(sugarValueList, Constant.SugarRecordType.AFTERBREAKFAST, Constant.SugarRecordType.AFTERLUNCH, Constant.SugarRecordType.AFTERDINNER);
//                        reachStandardCount += getReachStandardCount(values3, upper, lower);
//                        break;
//                    case BEFORE_SLEEP:
//                        List<Float> values5 = getSugarValues(sugarValueList, Constant.SugarRecordType.BEFORESLEEP);
//                        reachStandardCount += getReachStandardCount(values5, upper, lower);
//                        break;
//                    default:
//                        break;
//                }
//            }
            map.put(entry.getKey(), reachStandardCount * 100 / sugarValueList.size());
        }
        return map;
    }

    @Override
    public Map<Date, Integer> getPeriodControllerTargetsReachRate(Integer patientId, Date startDate, Date endDate, Map<Integer, DtrdEntRdSigninTargetDetail> targetDetails) {
        Map<Date, Integer> result = new HashMap<>();
        String startDateStr = DateUtils.date2Str(startDate, DateUtils.date_sdf.get());
        String endDateStr = DateUtils.date2Str(endDate, DateUtils.date_sdf.get());
        // region 查询所有的上下限
        LambdaQueryWrapper<DtrdEntRdUplowRecord> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdUplowRecord.class)
                .eq(DtrdEntRdUplowRecord::getIsDel, 0)
                .eq(DtrdEntRdUplowRecord::getPatientId, patientId);
        List<DtrdEntRdUplowRecord> uplowRecordList = list(queryWrapper);
        Map<Integer, DtrdEntRdUplowRecord> uplowRecordMap = null;
        if (CollectionUtil.isNotEmpty(uplowRecordList)) {
            uplowRecordMap = uplowRecordList.stream().collect(Collectors.toMap(
                    DtrdEntRdUplowRecord::getUplowRecordLimitType,
                    Function.identity(),
                    (key1, key2) -> key2));
        } else {
            uplowRecordMap = new HashMap<>();
        }
        // endregion 查询所有的上下限
        // 查询日期
        List<Date> dateList = DateUtils.getDateList(startDate, endDate);
        if (CollectionUtil.isEmpty(dateList)) {
            return null;
        }
        int dateSize = dateList.size();
        // 使用数组保存每天每项的数值
        float[] floats = new float[dateSize];
        // 查询到的周期数值
        for (Integer i : targetDetails.keySet()) {
            Constant.TargetProject targetProject = Constant.TargetProject.valueOf(i);
            floats = computeTargetReport(uplowRecordMap, patientId, startDateStr, endDateStr, dateList, floats, targetProject);
        }
        for (int i = 0; i < dateSize; i++) {
            if (targetDetails.size() == 0) {
                result.put(dateList.get(i), 0);
            } else {
                result.put(dateList.get(i), (int) (floats[i] * 100 / targetDetails.size()));
            }
        }
        return result;
    }

    /**
     * @param uplowRecordMap 获取上下限
     * @param patientId
     * @param startDate
     * @param endDate
     * @param dateList       起始到终止的日期列表
     * @param floats         每天的数值统计
     * @param targetProject  计算类型
     * @return
     */
    private float[] computeTargetReport(Map<Integer, DtrdEntRdUplowRecord> uplowRecordMap,
                                        Integer patientId, String startDate, String endDate, List<Date> dateList, float[] floats,
                                        Constant.TargetProject targetProject
    ) {
        assert floats.length == dateList.size();
        // 查询该项的上下限,将其转化为上下限的类型代码
        DtrdEntRdUplowRecord uplowRecord = null;
        Integer typeIndex = transformTypeFromTargetProject(targetProject);
        if (typeIndex != null) {
            uplowRecord = uplowRecordMap.get(typeIndex);
        }
        int dateSize = dateList.size();
        // 查询周期内的所有的数值
        Map<Date, List<Float>> searchValue = getControllerTargetDateValue(patientId, startDate, endDate, targetProject);
        for (int j = 0; j < dateSize; j++) {
            List<Float> temp = searchValue.get(dateList.get(j));
            // 如果没有设置上下限，有打卡记录则算达标
            if (uplowRecord == null) {
                if (CollectionUtil.isNotEmpty(temp)) {
                    floats[j]++;
                }
                continue;
            }
            // 如果设置了打卡记录，则计算其该项当天的平均达标率
            if (CollectionUtil.isNotEmpty(temp)) {
                int count = getReachStandardCount(temp, uplowRecord.getUplowRecordUpperValue(), uplowRecord.getUplowRecordLowerValue());
                floats[j] += (float) count / temp.size();
            }
        }
        return floats;
    }

    /**
     * 将targetProject类型转化为sugar上下限的type
     *
     * @param targetProject
     * @return
     */
    private Integer transformTypeFromTargetProject(Constant.TargetProject targetProject) {
        Integer integer = null;
        switch (targetProject) {
            case PBG:
                integer = UplowType.AFTER_MEAL.getType();
                break;
            case FBG:
                integer = UplowType.LIMOSIS.getType();
                break;
            default:
                // 默认为同名自动转化
                UplowType temp = UplowType.valueOfName(targetProject.getName());
                integer = temp != null ? temp.getType() : null;
        }
        return integer;
    }

    /**
     * 封装查询控制目标的日期，与日期打卡的列表值
     *
     * @param patientId
     * @param startDate
     * @param endDate
     * @param targetProject
     * @return
     */
    private Map<Date, List<Float>> getControllerTargetDateValue(Integer patientId, String startDate, String endDate, Constant.TargetProject targetProject) {
        Map<Date, List<Float>> result = new HashMap<>();
        List<DtrdEntRdArchiveLaboratory> laboratories = null;
        List<DtrdEntRdSigninSugarValue> signinSugarValues = null;
        List<DtrdEntRdSigninBloodPressure> bloodPressures = null;
        assert targetProject != null;
        switch (targetProject) {
            case BMI:
                // 完成
                // 查询周期内的所有的数值
                List<DtrdEntRdSigninHeightWeight> list = heightWeightRecordService.getPeriodHeightWeight(patientId, startDate, endDate);
                if (CollectionUtil.isNotEmpty(list)) {
                    result = list.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninHeightWeight::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninHeightWeight::getHeightWeightBmi,
                                            Collectors.toList())));
                }
                break;//BMI
            case WEIGHT:
                //完成
                List<DtrdEntRdSigninHeightWeight> heightWeightlist = heightWeightRecordService.getPeriodHeightWeight(patientId, startDate, endDate);
                if (CollectionUtil.isNotEmpty(heightWeightlist)) {
                    result = heightWeightlist.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninHeightWeight::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninHeightWeight::getHeightWeightWeight,
                                            Collectors.toList())));
                }
                break;// 体重(kg)
            case WAIST:
                // 计算腰围平均值
                List<DtrdEntRdSigninWaistline> waistlines = waistlineRecordService.getPeriodWaistLine(patientId, startDate, endDate);
                if (CollectionUtil.isNotEmpty(waistlines)) {
                    result = waistlines.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninWaistline::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninWaistline::getWaistlineValue,
                                            Collectors.collectingAndThen(Collectors.toList(),
                                                    p -> p.stream().map(Float::new).collect(Collectors.toList()))
                                    )));
                }
                break;// 腰围(cm)
            case HBA1C:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.HBA1C);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getHba1cDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getHba1c,
                                            Collectors.toList()
                                    )));
                }
                break;// 糖化血红蛋白(%)
            case FBG:
                // 完成

//                break;// "空腹血糖(mmol/L)
            case PBG:
                // 完成
                signinSugarValues = getPeriodSugarValueByType(patientId, startDate, endDate, targetProject);
                if (CollectionUtil.isNotEmpty(signinSugarValues)) {
                    result = signinSugarValues.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninSugarValue::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninSugarValue::getSugarValueSugarValue,
                                            Collectors.toList()
                                    )));
                }
                break;// "餐后血糖(mmol/L)")
            case PRESSURE_LOW:
//                // 已完成
                bloodPressures = getPeriodBloodPressure(patientId, startDate, endDate, targetProject);
                if (CollectionUtil.isNotEmpty(bloodPressures)) {
                    result = bloodPressures.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninBloodPressure::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage,
                                            Collectors.collectingAndThen(Collectors.toList(),
                                                    p -> p.stream().map(Float::new).collect(Collectors.toList()))
                                    )));
                }
                break;//"舒张压/低压 mmHg",
            case PRESSURE_HIGH:
                bloodPressures = getPeriodBloodPressure(patientId, startDate, endDate, targetProject);
                if (CollectionUtil.isNotEmpty(bloodPressures)) {
                    result = bloodPressures.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninBloodPressure::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure,
                                            Collectors.collectingAndThen(Collectors.toList(),
                                                    p -> p.stream().map(Float::new).collect(Collectors.toList()))
                                    )));
                }
                break;//"收缩压/高压 mmHg",
            case HEART_RATE:
                // 已完成
                bloodPressures = getPeriodBloodPressure(patientId, startDate, endDate, targetProject);
                if (CollectionUtil.isNotEmpty(bloodPressures)) {
                    result = bloodPressures.stream().collect(
                            Collectors.groupingBy(DtrdEntRdSigninBloodPressure::getRecordDate,
                                    Collectors.mapping(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate,
                                            Collectors.collectingAndThen(Collectors.toList(),
                                                    p -> p.stream().map(Float::new).collect(Collectors.toList()))
                                    )));
                }
                break;//"心率/脉搏(次/分钟)"
            case TC:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.TC);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getTcDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getTc,
                                            Collectors.toList()
                                    )));
                }
                break;//"总胆固醇(mmol/L)"),
            case TG:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.TG);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getTgDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getTg,
                                            Collectors.toList()
                                    )));
                }
                break;//"甘油三酯(mmol/L)"),
            case LDL:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.LDL_C);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getLdlcDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getLdlc,
                                            Collectors.toList()
                                    )));
                }
                break;//"低密度脂蛋白(mmol/L)"
            case HDL:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.HDL_C);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getHdlcDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getHdlc,
                                            Collectors.toList()
                                    )));
                }
                break;//"高密度脂蛋白(mmol/L)"
            case ALT:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.ALT);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getAltDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getAlt,
                                            Collectors.toList()
                                    )));
                }
                break;//"谷丙转氨酶(mmol/L)"),
            case BIL:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.TBIL);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getTbilDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getTbil,
                                            Collectors.toList()
                                    )));
                }
                break;//"总胆红素(mmol/L)"),
            case AST:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.AST);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getAstDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getAst,
                                            Collectors.toList()
                                    )));
                }
                break;//"谷草转氨酶(mmol/L)"),
            case ALP:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.ALP);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getAlpDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getAlp,
                                            Collectors.toList()
                                    )));
                }
                break;//"碱性磷酸酶(mmol/L)"),
            case UAE:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.UAE);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getUaeDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getUae,
                                            Collectors.toList()
                                    )));
                }
                break;//"尿微量白蛋白(mmol/L)"),
            case UAE_24H:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.UAE24);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getUae24Date,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getUae24,
                                            Collectors.toList()
                                    )));
                }
                break;//"24h尿白蛋白(mmol/L)"),
            case ACR:
                // 完成
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.ACR);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getAcrDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getAcr,
                                            Collectors.toList()
                                    )));
                }
                break;//"尿白蛋白/尿肌酐(mmol/L)"),
            case Cr:
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.CR);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getCrDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getCr,
                                            Collectors.toList()
                                    )));
                }
                break;//"血清肌酐(mmol/L)"),
            case UREANITROGEN:
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.UREA_NITROGEN);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getUreaNitrogenDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getUreaNitrogen,
                                            Collectors.toList()
                                    )));
                }
                break;//"尿素氮(mmol/L)"),
            case GFR:
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.GFR);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getGfrDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getGfr,
                                            Collectors.toList()
                                    )));
                }
                break;//"肾小球滤过率(mmol/L)"),
            case CrCl:
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.CREATININE_RATE);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getCreatinineRateDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getCreatinineRate,
                                            Collectors.toList()
                                    )));
                }
                break;//"内生肌酐清除率(mmol/L)"),
            case BUA:
                laboratories = laboratoryService.getPeriodLaboratoryType(patientId, startDate, endDate, Constant.LABORATORY.BUA);
                if (CollectionUtil.isNotEmpty(laboratories)) {
                    result = laboratories.stream().collect(
                            Collectors.groupingBy(DtrdEntRdArchiveLaboratory::getBuaDate,
                                    Collectors.mapping(DtrdEntRdArchiveLaboratory::getBua,
                                            Collectors.toList()
                                    )));
                }
                break;//"血尿酸(mmol/L)"),
            default:
//                targetReport.setReferenceValue("该对象还没进行枚举，请进行补充");
        }
        return result;
    }

    private List<DtrdEntRdSigninBloodPressure> getPeriodBloodPressure(Integer patientId, String startDate, String endDate, Constant.TargetProject targetProject) {
        LambdaQueryWrapper<DtrdEntRdSigninBloodPressure> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdSigninBloodPressure.class)
                .eq(DtrdEntRdSigninBloodPressure::getIsDel, 0)
                .eq(DtrdEntRdSigninBloodPressure::getPatientId, patientId)
                .ge(DtrdEntRdSigninBloodPressure::getRecordDate, startDate)
                .le(DtrdEntRdSigninBloodPressure::getRecordDate, endDate);
        switch (targetProject) {
            case PRESSURE_LOW:
//                // 已完成
                queryWrapper.isNotNull(DtrdEntRdSigninBloodPressure::getBloodPressureLowVoltage);
                break;//"舒张压/低压 mmHg",
            case PRESSURE_HIGH:
                queryWrapper.isNotNull(DtrdEntRdSigninBloodPressure::getBloodPressureHighPressure);
                break;//"收缩压/高压 mmHg",
            case HEART_RATE:
                // 已完成
                queryWrapper.isNotNull(DtrdEntRdSigninBloodPressure::getBloodPressureHeartRate);
                break;//"心率/脉搏(次/分钟)"
            default:
        }

        return bloodPressureRecordService.list(queryWrapper);
    }

    /**
     * 获取周期内指定类型的血糖记录
     *
     * @param patientId
     * @param startDate
     * @param endDate
     * @param targetProject
     * @return
     */
    private List<DtrdEntRdSigninSugarValue> getPeriodSugarValueByType(Integer patientId, String startDate, String endDate, Constant.TargetProject targetProject) {
        LambdaQueryWrapper<DtrdEntRdSigninSugarValue> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdSigninSugarValue.class)
                .isNotNull(DtrdEntRdSigninSugarValue::getSugarValueSugarValue)
                .eq(DtrdEntRdSigninSugarValue::getIsDel, 0)
                .eq(DtrdEntRdSigninSugarValue::getPatientId, patientId)
                .ge(DtrdEntRdSigninSugarValue::getRecordDate, startDate)
                .le(DtrdEntRdSigninSugarValue::getRecordDate, endDate);
        switch (targetProject) {
            case FBG:
                queryWrapper.in(DtrdEntRdSigninSugarValue::getSugarValueTimeTypeId, Constant.SugarRecordType.BEFOREBREAKFAST.getType());
                break;
            case PBG:
                queryWrapper.in(DtrdEntRdSigninSugarValue::getSugarValueTimeTypeId,
                        Constant.SugarRecordType.AFTERBREAKFAST.getType(),
                        Constant.SugarRecordType.AFTERLUNCH.getType(),
                        Constant.SugarRecordType.AFTERDINNER.getType());
            default:
        }
        return sugarRecordService.list(queryWrapper);
    }

    @Override
    public Integer getSugarReachStandardAvgRateByRange(Integer patientId, Date startDate, Date endDate) {
        Map<Date, Integer> map = getSugarReachStandard(patientId, startDate, endDate);
        if (MapUtil.isNotEmpty(map)) {
            Integer count = 0;
            for (Map.Entry<Date, Integer> entry : map.entrySet()) {
                count += entry.getValue();
            }
            int avgRate = count / map.size();
            log.info("DtrdENtRdRpLowRecordServiceImpl.getSugarReachStandardRateByRange 查询平均打卡的日期范围: {} ~ {}, patientId: {}, 达标率: {}%", DateUtil.formatDate(startDate), DateUtil.formatDate(endDate), patientId, avgRate);
            return avgRate;
        }
        return null;
    }

    @Override
    public Integer getSugarReachStandardRateThisWeek(Integer patientId) {
        // 今天
        List<Date> weekDate = DateUtils.getWeekDate(new Date());
        return getSugarReachStandardAvgRateByRange(patientId, weekDate.get(0), weekDate.get(6));
    }

    /**
     * 查询某些时间段下的血糖值
     */
    private List<Float> getSugarValues(List<DtrdEntRdSigninSugarValue> sugarValues, Constant.SugarRecordType... type) {
        List<Integer> types = Arrays.stream(type).map(Constant.SugarRecordType::getType)
                .collect(Collectors.toList());
        return sugarValues.stream()
                .filter(sv -> types.contains(sv.getSugarValueTimeTypeId()))
                .map(DtrdEntRdSigninSugarValue::getSugarValueSugarValue)
                .collect(Collectors.toList());
    }

    private Integer getReachStandardCount(List<Float> sugarValue, Float upper, Float lower) {
        int count = 0;
        if (CollectionUtil.isNotEmpty(sugarValue)) {
            for (Float value : sugarValue) {
                if (value <= upper && value >= lower) {
                    count++;
                }
            }
        }
        return count;
    }

    @Override
    public ValueUplowBean getSugarValueUpLowRecord(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdUplowRecord> queryWrapper = getBaseQueryWrapper()
                .eq(DtrdEntRdUplowRecord::getPatientId, patientId);
        List<DtrdEntRdUplowRecord> records = this.list(queryWrapper);
        log.info("DtrdEntRdUplowRecordServiceImpl.getSugarValueUpLowRecord.[patientId] " + records);
        return wrapperUplowRecords(records);
    }

    private ValueUplowBean wrapperUplowRecords(List<DtrdEntRdUplowRecord> records) {
        ValueUplowBean valueUplowBean = new ValueUplowBean();
        if (records.size() != 0) {
            for (DtrdEntRdUplowRecord uplowRecord : records) {
                Integer limitType = uplowRecord.getUplowRecordLimitType();
                switch (Objects.requireNonNull(UplowType.valueOf(limitType))) {
                    case WEE_HOURS:
                        valueUplowBean.setLowerValueWeeHours(wrappLimitValue(uplowRecord.getUplowRecordLowerValue(), UplowType.WEE_HOURS.getDefaultLimitLow()));
                        valueUplowBean.setUpperValueWeeHours(wrappLimitValue(uplowRecord.getUplowRecordUpperValue(), UplowType.WEE_HOURS.getDefaultLimitUp()));
                        break;
                    case LIMOSIS:
                        valueUplowBean.setLowerValueLimosis(wrappLimitValue(uplowRecord.getUplowRecordLowerValue(), UplowType.LIMOSIS.getDefaultLimitLow()));
                        valueUplowBean.setUpperValueLimosis(wrappLimitValue(uplowRecord.getUplowRecordUpperValue(), UplowType.LIMOSIS.getDefaultLimitUp()));
                        break;
                    case AFTER_MEAL:
                        valueUplowBean.setLowerValueAfterMeal(wrappLimitValue(uplowRecord.getUplowRecordLowerValue(), UplowType.AFTER_MEAL.getDefaultLimitLow()));
                        valueUplowBean.setUpperValueAfterMeal(wrappLimitValue(uplowRecord.getUplowRecordUpperValue(), UplowType.AFTER_MEAL.getDefaultLimitUp()));
                        break;
                    case BEFORE_SLEEP:
                        valueUplowBean.setLowerValueBeforeSleep(wrappLimitValue(uplowRecord.getUplowRecordLowerValue(), UplowType.BEFORE_SLEEP.getDefaultLimitLow()));
                        valueUplowBean.setUpperValueBeforeSleep(wrappLimitValue(uplowRecord.getUplowRecordUpperValue(), UplowType.BEFORE_SLEEP.getDefaultLimitUp()));
                        break;
                    case BEFORE_MEAL:
                        valueUplowBean.setLowerValueBeforeMeal(wrappLimitValue(uplowRecord.getUplowRecordLowerValue(), UplowType.BEFORE_MEAL.getDefaultLimitLow()));
                        valueUplowBean.setUpperValueBeforeMeal(wrappLimitValue(uplowRecord.getUplowRecordUpperValue(), UplowType.BEFORE_MEAL.getDefaultLimitUp()));
                        break;
                    case PRESSURE_HIGH:
                        valueUplowBean.setLowerValueHighPressure(uplowRecord.getUplowRecordLowerValue().intValue());
                        valueUplowBean.setUpperValueHighPressure(uplowRecord.getUplowRecordUpperValue().intValue());
                        break;
                    case PRESSURE_LOW:
                        valueUplowBean.setLowerValueLowPressure(uplowRecord.getUplowRecordLowerValue().intValue());
                        valueUplowBean.setUpperValueLowPressure(uplowRecord.getUplowRecordUpperValue().intValue());
                        break;
                    case BMI:
                        valueUplowBean.setLowerValueBmi(uplowRecord.getUplowRecordLowerValue());
                        valueUplowBean.setUpperValueBmi(uplowRecord.getUplowRecordUpperValue());
                        break;
                    default:
                        break;
                }
            }
        }
        return valueUplowBean;
    }

    private float wrappLimitValue(Float value, float defaultValue) {
        return value == null ? defaultValue : value;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveOrUpdateUplowRecord(ValueUplowBean sugarValueUplow) {
        Integer doctorId = sugarValueUplow.getDoctorId();
        Integer patientId = sugarValueUplow.getPatientId();
        //region 凌晨血糖
        LambdaQueryWrapper<DtrdEntRdUplowRecord> weeHoursQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.WEE_HOURS.getType());
        DtrdEntRdUplowRecord weeHoursUplowRecord = this.getOne(weeHoursQueryWrapper);
        if (weeHoursUplowRecord == null) {
            weeHoursUplowRecord = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            weeHoursUplowRecord.setUplowRecordLimitType(UplowType.WEE_HOURS.getType());
        }
        weeHoursUplowRecord.setUplowRecordUpperValue(sugarValueUplow.getUpperValueWeeHours());
        weeHoursUplowRecord.setUplowRecordLowerValue(sugarValueUplow.getLowerValueWeeHours());
        boolean weeHoursResult = this.saveOrUpdate(weeHoursUplowRecord);
        //endregion
        //region 空腹血糖
        LambdaQueryWrapper<DtrdEntRdUplowRecord> limosisQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.LIMOSIS.getType());
        DtrdEntRdUplowRecord limosisUplowRecord = this.getOne(limosisQueryWrapper);
        if (limosisUplowRecord == null) {
            limosisUplowRecord = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            limosisUplowRecord.setUplowRecordLimitType(UplowType.LIMOSIS.getType());
        }
        limosisUplowRecord.setUplowRecordUpperValue(sugarValueUplow.getUpperValueLimosis());
        limosisUplowRecord.setUplowRecordLowerValue(sugarValueUplow.getLowerValueLimosis());
        boolean limosisResult = this.saveOrUpdate(limosisUplowRecord);
        //endregion学
        //region 餐后血糖
        LambdaQueryWrapper<DtrdEntRdUplowRecord> afterMealQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.AFTER_MEAL.getType());
        DtrdEntRdUplowRecord afterMealUplowRecord = this.getOne(afterMealQueryWrapper);
        if (afterMealUplowRecord == null) {
            afterMealUplowRecord = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            afterMealUplowRecord.setUplowRecordLimitType(UplowType.AFTER_MEAL.getType());
        }
        afterMealUplowRecord.setUplowRecordUpperValue(sugarValueUplow.getUpperValueAfterMeal());
        afterMealUplowRecord.setUplowRecordLowerValue(sugarValueUplow.getLowerValueAfterMeal());
        boolean afterMealResult = this.saveOrUpdate(afterMealUplowRecord);
        //endregion
        //region 睡前血糖
        LambdaQueryWrapper<DtrdEntRdUplowRecord> beforeSleepQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.BEFORE_SLEEP.getType());
        DtrdEntRdUplowRecord beforeSleepUplowRecord = this.getOne(beforeSleepQueryWrapper);
        if (beforeSleepUplowRecord == null) {
            beforeSleepUplowRecord = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            beforeSleepUplowRecord.setUplowRecordLimitType(UplowType.BEFORE_SLEEP.getType());
        }
        beforeSleepUplowRecord.setUplowRecordUpperValue(sugarValueUplow.getUpperValueBeforeSleep());
        beforeSleepUplowRecord.setUplowRecordLowerValue(sugarValueUplow.getLowerValueBeforeSleep());
        boolean beforeSleepResult = this.saveOrUpdate(beforeSleepUplowRecord);
        //endregion
        //region 餐前血糖
        LambdaQueryWrapper<DtrdEntRdUplowRecord> beforeMealQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.BEFORE_MEAL.getType());
        DtrdEntRdUplowRecord beforeMealUplowRecord = this.getOne(beforeMealQueryWrapper);
        if (beforeMealUplowRecord == null) {
            beforeMealUplowRecord = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            beforeMealUplowRecord.setUplowRecordLimitType(UplowType.BEFORE_MEAL.getType());
        }
        beforeMealUplowRecord.setUplowRecordUpperValue(sugarValueUplow.getUpperValueBeforeMeal());
        beforeMealUplowRecord.setUplowRecordLowerValue(sugarValueUplow.getLowerValueBeforeMeal());
        boolean beforeMealResult = this.saveOrUpdate(beforeMealUplowRecord);
        //endregion
        //region 收缩压/高压
        LambdaQueryWrapper<DtrdEntRdUplowRecord> pressureHighQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.PRESSURE_HIGH.getType());
        DtrdEntRdUplowRecord highPressureLimit = this.getOne(pressureHighQueryWrapper);
        if (highPressureLimit == null) {
            highPressureLimit = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            highPressureLimit.setUplowRecordLimitType(UplowType.PRESSURE_HIGH.getType());
        }
        highPressureLimit.setUplowRecordUpperValue(sugarValueUplow.getUpperValueHighPressure().floatValue());
        highPressureLimit.setUplowRecordLowerValue(sugarValueUplow.getLowerValueHighPressure().floatValue());
        saveOrUpdate(highPressureLimit);
        //endregion
        //region 舒张压/低压
        LambdaQueryWrapper<DtrdEntRdUplowRecord> pressureLowQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.PRESSURE_LOW.getType());
        DtrdEntRdUplowRecord pressureLowLimit = this.getOne(pressureLowQueryWrapper);
        if (pressureLowLimit == null) {
            pressureLowLimit = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            pressureLowLimit.setUplowRecordLimitType(UplowType.PRESSURE_LOW.getType());
        }
        pressureLowLimit.setUplowRecordUpperValue(sugarValueUplow.getUpperValueLowPressure().floatValue());
        pressureLowLimit.setUplowRecordLowerValue(sugarValueUplow.getLowerValueLowPressure().floatValue());
        saveOrUpdate(pressureLowLimit);
        //endregion
        //region bmi
        LambdaQueryWrapper<DtrdEntRdUplowRecord> bmiQueryWrapper = getRecordQueryWrapper(doctorId, patientId)
                .eq(DtrdEntRdUplowRecord::getUplowRecordLimitType, UplowType.BMI.getType());
        DtrdEntRdUplowRecord bmiLimit = this.getOne(bmiQueryWrapper);
        if (bmiLimit == null) {
            bmiLimit = new DtrdEntRdUplowRecord(doctorId, patientId).init();
            bmiLimit.setUplowRecordLimitType(UplowType.BMI.getType());
        }
        bmiLimit.setUplowRecordUpperValue(sugarValueUplow.getUpperValueBmi());
        bmiLimit.setUplowRecordLowerValue(sugarValueUplow.getLowerValueBmi());
        saveOrUpdate(bmiLimit);
        //endregion
        return weeHoursResult && limosisResult && afterMealResult && beforeMealResult && beforeSleepResult;
    }

    @Override
    public float[] getSystolicPressure(Integer patientId) {
        DtrdEntRdUplowRecord result = baseMapper.getSystolicPressureByPatientId(patientId);
        float[] systolicPressure = new float[2];
        if (result != null) {
            systolicPressure[0] = result.getUplowRecordLowerValue();
            systolicPressure[1] = result.getUplowRecordUpperValue();
        } else {
            systolicPressure[0] = UplowType.PRESSURE_HIGH.getDefaultLimitUp();
            systolicPressure[1] = UplowType.PRESSURE_HIGH.getDefaultLimitLow();
        }
        return systolicPressure;
    }

    @Override
    public float[] getDiastolicPressure(Integer patientId) {
        DtrdEntRdUplowRecord result = baseMapper.getDiastolicPressureByPatientId(patientId);
        float[] diastolicPressure = new float[2];
        if (result != null) {
            diastolicPressure[0] = result.getUplowRecordLowerValue();
            diastolicPressure[1] = result.getUplowRecordUpperValue();
        } else {
            diastolicPressure[0] = UplowType.PRESSURE_LOW.getDefaultLimitUp();
            diastolicPressure[1] = UplowType.PRESSURE_LOW.getDefaultLimitLow();
        }
        return diastolicPressure;
    }

    private LambdaQueryWrapper<DtrdEntRdUplowRecord> getRecordQueryWrapper(Integer doctorId, Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdUplowRecord> wrapper = getBaseQueryWrapper()
                .eq(DtrdEntRdUplowRecord::getPatientId, patientId);
        if (doctorId != null) {
            wrapper.eq(DtrdEntRdUplowRecord::getDoctorId, doctorId);
        }
        return wrapper;
    }

    private LambdaQueryWrapper<DtrdEntRdUplowRecord> getBaseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdUplowRecord.class)
                .eq(DtrdEntRdUplowRecord::getIsDel, 0);
    }
}
